//
//  DateUtil.swift
//  Health-Doctor
//
//  Created by TinyThyTiger on 2019/1/4.
//  Copyright © 2019 Leon. All rights reserved.
//

import Foundation


struct DateUtil{
    
    
    ///获取当前日期字符串，默认 yyyy-MM-dd
    static func currentDate(format:String = "yyyy-MM-dd") -> String {
        let date = Date()
        let timeFormatter = getFormat()
        timeFormatter.dateFormat = format
        let valDate = timeFormatter.string(from: date)
        return valDate
    }
    
    ///获取当前日期时间时间，默认 yyyy-MM-dd HH:mm:ss
    static func currentDateTime(format:String="yyyy-MM-dd HH:mm:ss") ->String {
        return self.currentDate(format: format)
    }
    
    ///和系统时间保持一致（默认北京时间）
    static func currentDate_UTC() -> Date{
        let format = "yyyy-MM-dd HH:mm:ss"
        let dateString = DateUtil.currentDate(format: format)
        let dateFormatter = DateFormatter.init()
        //这个会产生时差
//        let timeZone = TimeZone.init(identifier: "Asia/Shanghai")
        let timeZone = TimeZone.init(identifier: "UTC")
        dateFormatter.locale = Locale.init(identifier: "zh_CN")
        dateFormatter.timeZone = timeZone
        dateFormatter.dateFormat = format
        let date = dateFormatter.date(from: dateString)
        return date ?? Date()
    }
    
    ///把 yyyy/MM/dd格式的日期转换为 yyyy-MM-dd格式的日期
    static func convertDateFormater(_ date: String) -> String{
        let dateFormatter = getFormat()
        dateFormatter.dateFormat = "yyyy/MM/dd"
        let newdate = dateFormatter.date(from: date)
        
        dateFormatter.dateFormat = "yyyy-MM-dd"
        return  dateFormatter.string(from: newdate!)
    }
    
    /// 时间戳转Date
    static func getDateFrom(timeStamp:String) ->Date {
        let interval:TimeInterval = TimeInterval.init(timeStamp)!
        return Date(timeIntervalSince1970: interval)
    }
    
    ///返回时间（今天，昨天....）
    static func chatTimeString(timeInterval: TimeInterval) -> String{
        if timeInterval <= 0{
            return ""
        }
        //如果服务端返回的时间戳精确到毫秒，需要除以1000,否则不需要
        let date = Date(timeIntervalSince1970: timeInterval)
        
        let formatter = DateFormatter()
        if date.isToday() {
            //是今天
            formatter.dateFormat = "今天HH:mm"
            return formatter.string(from: date)
            
        }else if date.isYesterday(){
            //是昨天
            formatter.dateFormat = "昨天HH:mm"
            return formatter.string(from: date)
        }else if date.isSameWeek(){
            //是同一周
            let week = date.weekdayStringFromDate()
            formatter.dateFormat = "\(week)HH:mm"
            return formatter.string(from: date)
        }else{
            formatter.dateFormat = "yyyy-MM-dd HH:mm"
            return formatter.string(from: date)
        }
    }
    
    
    //获取当前时间
    static func getCurrentTime(dateFormat:String="yyyy-MM-dd HH:mm:ss") ->String {
        let formatter = getFormat()
        formatter.dateFormat = dateFormat
        let now = formatter.string(for: Date()) ?? ""
        return now
    }
    
    //获取通用(已通过测试，不要乱修改，否则要测试)
    static func getFormat()->DateFormatter{
        let formatter = DateFormatter()
        formatter.locale = NSLocale.system
        formatter.calendar = Calendar(identifier: .gregorian)
        return formatter
    }
    //获取明天时间
    static func getTomorrowCurrentTime(dateFormat:String="yyyy-MM-dd HH:mm:ss") ->String {
        let formatter = getFormat()
        formatter.dateFormat = dateFormat
        let now = formatter.string(for: Date()) ?? ""
        // 先把传入的时间转为 date
        let date = formatter.date(from: now)
        
        let nextTime: TimeInterval = 24*60*60
        if let nextDate = date?.addingTimeInterval(nextTime){
            let nextDay = formatter.string(from: nextDate)
            return nextDay
        }
        return ""
    }
    
    //获取后天时间
    static func getAfterTomorrowCurrentTime(dateFormat:String="yyyy-MM-dd HH:mm:ss") ->String {
        let formatter = getFormat()
        formatter.dateFormat = dateFormat
        let now = formatter.string(for: Date())!
        // 先把传入的时间转为 date
        let date = formatter.date(from: now)
        
        let nextTime: TimeInterval = 24*60*60*2
        let nextDate = date?.addingTimeInterval(nextTime)
        let nextDay = formatter.string(from: nextDate!)
        return nextDay
    }
    
    //获取当前时间戳字符串
    static func getNowTimeStampMillisecond() -> String {
        let formatter = getFormat()
        formatter.dateStyle = .medium
        formatter.timeStyle = .short
        formatter.dateFormat = "YYYY-MM-dd HH:mm:ss"
        let timeZone = TimeZone.init(identifier: "Asia/Shanghai")
        formatter.timeZone = timeZone
        let dateNow = Date()//当前时间
        let timeInterval:TimeInterval = dateNow.timeIntervalSince1970
        let dateInt:Int = Int(timeInterval)
        let timeStamp = String.init(format: "%ld", dateInt)+"000"
        return timeStamp
    }
    
    ///string转date,这里写的不严谨，该方法可能转换失败返回nil，若此时修改，但项目中涉及范围太广了，没法了(可使用stringToDate)
    ///这里返回的时间是UTC时间，用dateConvertString方法可以翻转解析成功成正确的字符串
    static func stringConvertDate(string:String, dateFormat:String="yyyy-MM-dd HH:mm:ss") -> Date {
        var string = string
        
        let dateFormatter = getFormat()
        dateFormatter.dateFormat = dateFormat
        
        if !string.isEmpty{
            //容错处理
            if dateFormat.count == 10 && string.count > 10{
                string = string.subString(to: 10)
            }
            if let date = dateFormatter.date(from: string){
                return date
            }
            //容错处理
            let fromat = getFormateBy(string)
            dateFormatter.dateFormat = fromat
            if let date = dateFormatter.date(from: string){
                return date
            }
        }
        
        //再次容错
        if dateFormat == "yyyy-MM-dd" {
            string = "1970-01-01"
        }else if dateFormat == "yyyy-MM-dd HH:mm:ss"{
            string = "1970-01-01 00:00:00"
        }else if dateFormat == "yyyy/MM/dd" {
            string = "1970/01/01"
        }
        return dateFormatter.date(from: string)!
    }
    

    ///根据时间字符串获取对应的格式(内部自动根据内容格式化)
    static func getFormateBy(_ dateStr:String)->String?{
        if dateStr.isEmpty{return nil}
        var date = dateStr
        if dateStr.count > 19{
            //"2022-09-13 14:45:13:269"
            date = dateStr.subString(to: 19)
        }
        let r1 = date.isMatch(pattern: "^\\d{4}-\\d{2}-\\d{2}$")
        if r1{return "yyyy-MM-dd"}
        
        let r1_1 = date.isMatch(pattern: "^\\d{4}年\\d{2}月\\d{2}日$")
        if r1_1{return "yyyy年MM月dd日"}
        
        let r2 = date.isMatch(pattern: "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$")
        if r2{return "yyyy-MM-dd HH:mm:ss"}
        
        let r3 = date.isMatch(pattern: "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$")
        if r3{return "yyyy-MM-dd HH:mm"}
        
        let re4 = date.isMatch(pattern: "^\\d{4}/\\d{2}/\\d{2}$")
        if re4{return "yyyy/MM/dd"}
        
        let re5 = date.isMatch(pattern: "^\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}:\\d{2}$")
        if re5{return "yyyy/MM/dd HH:mm:ss"}
        
        let re6 = date.isMatch(pattern: "^\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}$")
        if re6{return "yyyy/MM/dd HH:mm"}
        
        return nil
    }
    
    
    //时间戳转时间(秒)
    static func timeString(timeInterval: TimeInterval, dateFormat:String="yyyy-MM-dd HH:mm:ss") -> String{
        //如果服务端返回的时间戳精确到毫秒，需要除以1000,否则不需要
        let date = Date(timeIntervalSince1970: timeInterval)
        
        let formatter = DateFormatter()
        let timeZone = TimeZone.init(identifier: "Asia/Shanghai")
        formatter.locale = Locale.init(identifier: "zh_CN")
        formatter.timeZone = timeZone
        
        formatter.dateFormat = dateFormat
        return formatter.string(from: date)
    }
    
    ///时间转时间戳函数
    static func timeToTimeStamp(time: String ,dateFormat:String="yyyy-MM-dd HH:mm:ss") -> Double {
        if time.isEmpty {
            return 0
        }
        var newtime = ""
        if time.contains(".") {
            let timeArr = time.split(separator: ".").map(String.init)
            newtime = timeArr[0]
        }else {
            newtime = time
        }
        let dfmatter = DateFormatter()
        let timeZone = TimeZone.init(identifier: "Asia/Shanghai")
        dfmatter.locale = Locale.init(identifier: "zh_CN")
        dfmatter.timeZone = timeZone
        //设定时间格式,这里可以设置成自己需要的格式
        dfmatter.dateFormat = dateFormat
        let last = dfmatter.date(from: newtime)
        let timeStamp = last?.timeIntervalSince1970
        return timeStamp!
    }
    
    ///两个日期比较
    static func compareTime(date1:Date, date2:Date) -> Int {
        if date1.compare(date2) == .orderedAscending {
            // date1 < date2 升序排列
            return -1
        }else if date1.compare(date2) == .orderedSame {
            //date1 = date2 相等
            return 0
        }else {
            //降序排列的 date1 > date2 降序排列
            return 1
        }
    }
    
    ///是否为今年
    static func isThisYear(date: Date) -> Bool {
        let calendar = Calendar.current
        let nowCmps = calendar.dateComponents([.year], from: Date())
        let selfCmps = calendar.dateComponents([.year], from: date)
        let result = nowCmps.year == selfCmps.year
        return result
    }
    
    ///是否是今天
    static func isToday(time: String) ->Bool {
        let today = DateUtil.stringConvertDate(string: String(DateUtil.getCurrentTime().prefix(10)), dateFormat: "yyyy-MM-dd")
        let timeDate = DateUtil.stringConvertDate(string: String(time.prefix(10)), dateFormat: "yyyy-MM-dd")
        if Calendar.current.isDate(today, inSameDayAs: timeDate) {
            return true
        }else {
            return false
        }
    }
    
    ///返回两个日期 相隔多少小时
    static func hourInterval(startTime:String,endTime:String,dateFormat:String = "yyyy-MM-dd HH:mm:ss") -> Int{
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = dateFormat
        guard let date1 = dateFormatter.date(from: startTime),
              let date2 = dateFormatter.date(from: endTime) else {
            return -1
        }
        let components = NSCalendar.current.dateComponents([.hour], from: date1, to: date2)
        return components.hour ?? -1
    }
    
    ///返回两个日期 相隔多少分钟
    static func minuteInterval(startTime:String,endTime:String,dateFormat:String = "yyyy-MM-dd HH:mm:ss") -> Int{
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = dateFormat
        guard let date1 = dateFormatter.date(from: startTime),
              let date2 = dateFormatter.date(from: endTime) else {
            return -1
        }
        let components = NSCalendar.current.dateComponents([.minute], from: date1, to: date2)
        return components.minute ?? -1
    }
    
    ///返回两个日期 相隔多少天 相差多少天  时间加减
    static func dayInterval(startTime:String,endTime:String,dateFormat:String = "yyyy-MM-dd") -> Int{
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = dateFormat
        guard let date1 = dateFormatter.date(from: startTime),
              let date2 = dateFormatter.date(from: endTime) else {
            return -1
        }
        let components = NSCalendar.current.dateComponents([.day], from: date1, to: date2)
        return components.day ?? -1
    }
    
    ///返回两个日期 相隔多少周
    static func weekInterval(startTime:String,endTime:String) -> Int{
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        guard let date1 = dateFormatter.date(from: startTime),
              let date2 = dateFormatter.date(from: endTime) else {
            return -1
        }
        let components = NSCalendar.current.dateComponents([.weekOfYear], from: date1, to: date2)
        return components.weekOfYear ?? -1
    }
    
    ///返回两个日期相隔多少个月
    static func monthInterval(startTime:String,endTime:String, _ format:String? = "yyyy-MM-dd HH:mm:ss") -> Int{
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = format
        guard let date1 = dateFormatter.date(from: startTime),
              let date2 = dateFormatter.date(from: endTime) else {
            return -1
        }
        let components = NSCalendar.current.dateComponents([.month], from: date1, to: date2)
        return components.month ?? -1
    }
    
    ///返回两个日期，相隔多少年
    static func yearInterval(startTime:String,endTime:String,_ format:String? = "yyyy-MM-dd") -> Int{
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = format
        guard let date1 = dateFormatter.date(from: startTime),
              let date2 = dateFormatter.date(from: endTime) else {
            return -1
        }
        let components = NSCalendar.current.dateComponents([.year], from: date1, to: date2)
        
        return components.year!
    }
    
    
    ///返回一个日期时间多少年前的日期时间，比如2022-01-01  year=2  返回2020-01-01
    static func anyFewYearsTime(dateTime:String,year:Int)-> String{
        
        var  dateStrArr = dateTime.split(separator: "-").map(String.init)
        if let yearStr = dateStrArr.first,yearStr.isNum(){
            dateStrArr[0] = "\(yearStr.intValue() - year)"
            return dateStrArr.joined(separator: "-")
        }
        return ""
    }
    
    ///返回一个当前日期时间，多少年之前的日期时间
    static func anyFewYearsAgoTime(year:Int,format:String = "yyyy-MM-dd")->String{
        let currentDateTime = DateUtil.currentDateTime(format:format)
        return self.anyFewYearsTime(dateTime:currentDateTime, year:year)
    }
    
    ///返回当前日期后，往后推 多少年、月、日后的日期（比如一个月后的今天） 负数就是往前推，正数就是往后推
    static func getDateLastDate(date:Date,year:Int? = 0,month:Int? = 0,days:Int? = 0,format:String = "yyyy-MM-dd") ->String{
        let calendar = NSCalendar(calendarIdentifier: .gregorian)
        var adcomps = DateComponents()
        if let year = year {
            adcomps.year = year
        }
        if let month = month {
            adcomps.month = month
        }
        if let days = days {
            adcomps.day = days
        }
        
        let data = calendar!.date(byAdding: adcomps as DateComponents, to:date, options: NSCalendar.Options(rawValue: 0))
        
        let formatter = DateFormatter()
        formatter.dateFormat = format
        
        return formatter.string(for: data)!
        
    }
    
    ///是否是老年人  判断是否是老年人  判断老年人
    static func isOldYear(birthday: String?)->Bool{
        guard let birthday = birthday else {
            return false
        }
        if birthday.count < 4 {
            return false
        }
        
        let yearStr = birthday.subString(to: 4).intValue()
        let curYear = DateUtil.getCurrentTime().subString(to: 4).intValue()
        let year = curYear - yearStr
        return year >= 65
    }
    
    
    ///通过生日计算年龄(会精准到月)，已经测试，项目所有年龄计算都精准到月，不要轻易修改
    static func caculateAge(birthday: String) -> Int{
        if birthday.isEmpty{return 0}
        let newBirthday = String(birthday.prefix(10))
        //格式化日期
        let d_formatter = DateFormatter()
        d_formatter.dateFormat = "yyyy-MM-dd"
        d_formatter.timeZone = TimeZone.init(abbreviation: "UTC")
        var birthDay_date = d_formatter.date(from: newBirthday)
        
        if birthDay_date == nil {
            let d_formatter_withtime = DateFormatter()
            d_formatter_withtime.dateFormat = "yyyy-MM-dd hh:mm:ss"
            d_formatter_withtime.timeZone = TimeZone.init(abbreviation: "UTC")
            birthDay_date = d_formatter_withtime.date(from: newBirthday)
        }
        
        // 出生日期转换 年月日
        if let tempBirthDay_date = birthDay_date {
            let birthdayDate = Calendar.current.dateComponents([.year,.month,.day], from: tempBirthDay_date)
            let brithDateYear  = birthdayDate.year
            let brithDateDay   = birthdayDate.day
            let brithDateMonth = birthdayDate.month
            // 获取系统当前 年月日
            let currentDate = Calendar.current.dateComponents([.year,.month,.day], from: Date())
            let currentDateYear  = currentDate.year
            let currentDateDay   = currentDate.day
            let currentDateMonth = currentDate.month
            // 计算年龄
            var iAge = currentDateYear! - brithDateYear! - 1
            if ((currentDateMonth! > brithDateMonth!) || (currentDateMonth! == brithDateMonth! && currentDateDay! >= brithDateDay!)) {
                iAge += 1
            }
            return iAge
        }
        //计算错误
        return 0
    }
    
    
    /// 根据本地时区转换(把一个时间，转换成现在时间)
    static func getNowDateFromatAnDate(_ anyDate: Date?) -> Date? {
        //设置源日期时区
        let sourceTimeZone = NSTimeZone(abbreviation: "UTC")
        //或GMT
        //设置转换后的目标日期时区
        let destinationTimeZone = NSTimeZone.local as NSTimeZone
        //得到源日期与世界标准时间的偏移量
        var sourceGMTOffset: Int? = nil
        if let aDate = anyDate {
            sourceGMTOffset = sourceTimeZone?.secondsFromGMT(for: aDate)
        }
        //目标日期与本地时区的偏移量
        var destinationGMTOffset: Int? = nil
        if let aDate = anyDate {
            destinationGMTOffset = destinationTimeZone.secondsFromGMT(for: aDate)
        }
        //得到时间偏移量的差值
        let interval = TimeInterval((destinationGMTOffset ?? 0) - (sourceGMTOffset ?? 0))
        //转为现在时间
        var destinationDateNow: Date? = nil
        if let aDate = anyDate {
            destinationDateNow = Date(timeInterval: interval, since: aDate)
        }
        return destinationDateNow
    }
    
    /// 时间比较，是否升序<，时间越往后越大
    static func compareASC(date1:Date,date2:Date)->Bool{
        if date1.compare(date2) == .orderedAscending{
            return true
        }
        return false
    }
    ///时间比较，是否降序>，时间越往后越大
    static func compareDESC(date1:Date,date2:Date)->Bool{
        if date1.compare(date2) == .orderedDescending{
            return true
        }
        return false
    }
    
}

extension Date {

    ///是否是今天
    func isToday() -> Bool {
        let calendar = Calendar.current
        //当前时间
        let nowComponents = calendar.dateComponents([.day,.month,.year], from: Date() )
        //self
        let selfComponents = calendar.dateComponents([.day,.month,.year], from: self as Date)
        
        return (selfComponents.year == nowComponents.year) && (selfComponents.month == nowComponents.month) && (selfComponents.day == nowComponents.day)
    }
    
    ///是否是昨天
    func isYesterday() -> Bool {
        let calendar = Calendar.current
        //当前时间
        let nowComponents = calendar.dateComponents([.day], from: Date() )
        //self
        let selfComponents = calendar.dateComponents([.day], from: self as Date)
        let cmps = calendar.dateComponents([.day], from: selfComponents, to: nowComponents)
        return cmps.day == 1
        
    }
    
    func isSameWeek() -> Bool {
        let calendar = Calendar.current
        //当前时间
        let nowComponents = calendar.dateComponents([.day,.month,.year], from: Date())
        //self
        let selfComponents = calendar.dateComponents([.weekday,.month,.year], from: self as Date)
        
        return (selfComponents.year == nowComponents.year) && (selfComponents.month == nowComponents.month) && (selfComponents.weekday == nowComponents.weekday)
    }
    
    /// 是不是今年
    func isSameYear() -> Bool {
        let calendar = Calendar.current
        //当前时间
        let nowComponents = calendar.dateComponents([.year], from: Date() )
        //self
        let selfComponents = calendar.dateComponents([.year], from: self as Date)
        
        return (selfComponents.year == nowComponents.year)
    }
    
    /// 是不是当月
    func isSameMonth() -> Bool {
        let calendar = Calendar.current
        //当前时间
        let nowComponents = calendar.dateComponents([.day,.month,.year], from: Date() )
        //self
        let selfComponents = calendar.dateComponents([.day,.month,.year], from: self as Date)
        
        return (selfComponents.year == nowComponents.year) && (selfComponents.month == nowComponents.month)
    }
    
    ///获取星期几
    func weekdayStringFromDate() -> String {
        let weekdays:NSArray = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]
        var calendar = Calendar.init(identifier: .gregorian)
        let timeZone = TimeZone.init(identifier: "Asia/Shanghai")
        calendar.timeZone = timeZone!
        let theComponents = calendar.dateComponents([.weekday], from: self as Date)
        let index = theComponents.weekday! - 1
        return weekdays.object(at:index) as! String
    }
    
    
    ///获取时间戳
    func timeStamp() -> String{
        let timeInterval = self.timeIntervalSince1970
        let timeStamp = Int(timeInterval)
        return "\(timeStamp)"
    }

    /// 获取当前 毫秒级 时间戳 - 13位
    func milliStamp()-> String {
        let timeInterval: TimeInterval = self.timeIntervalSince1970
        let millisecond = CLongLong(round(timeInterval*1000))
        return "\(millisecond)"
    }

    ///返回当前日期 的一个小时之后的日期
    func nextHourDate() -> Date {
        var components = Calendar.current.dateComponents([.year,.month,.day,.hour], from:self)
        components.hour = components.hour! + 1
        return Calendar.current.date(from: components)!
    }
}
